package service

import (
	myerror "CodeCover/internal/errors"
	"CodeCover/internal/models"
	"CodeCover/internal/utils"
	"context"
	"path/filepath"
)

// 任务sql repo
type TaskSqlRepository interface {
	Create(ctx context.Context, task *models.Task) error
	GetByTid(ctx context.Context, tid string) (*models.Task, error)
	FindAllByName(ctx context.Context, username string, page int, pageSize int, start string, end string) ([]models.Task, error)
	// GetStateByID(ctx context.Context, tid string) (state int, err error)
	UpdatePathByTid(ctx context.Context, tid, absPath string) error
	UpdatePercentById(ctx context.Context, tid string, total int, cover int, percent float64) error
}

// 任务 nosql repo
// type TaskNosqlRepository interface {
// 	Create(ctx context.Context, task *models.Task)
// }

type TaskService struct {
	sqlTaskRepo TaskSqlRepository
	// nosqlTaskRepo TaskNosqlRepository
}

func NewTaskService(sqlTaskRepo TaskSqlRepository) *TaskService {
	return &TaskService{sqlTaskRepo: sqlTaskRepo}
}

func (s *TaskService) Create(ctx context.Context, t *models.Task) error {
	if err := s.sqlTaskRepo.Create(ctx, t); err != nil {
		if customErr, ok := err.(*myerror.CustomError); ok {
			return &myerror.CustomError{
				Code:        customErr.Code,
				Message:     "TaskService:Create() failed",
				OriginError: err,
				Metadata: map[string]any{
					"task": t,
				},
			}
		} else {
			return &myerror.CustomError{
				Code:        myerror.DefaultFailure,
				Message:     "TaskService:Create() failed",
				OriginError: err,
				Metadata: map[string]any{
					"task": t,
				},
			}
		}
	}

	return nil
}

func (s *TaskService) GetTaskByTid(ctx context.Context, tid string) (*models.Task, error) {
	task, err := s.sqlTaskRepo.GetByTid(ctx, tid)
	if err != nil {
		if customErr, ok := err.(*myerror.CustomError); ok {
			return nil, &myerror.CustomError{
				Code:        customErr.Code,
				Message:     "TaskService:GetTaskByTid() failed",
				OriginError: err,
				Metadata: map[string]any{
					"tid": tid,
				},
			}
		} else {
			return nil, &myerror.CustomError{
				Code:        myerror.DefaultFailure,
				Message:     "TaskService:GetTaskByTid() failed",
				OriginError: err,
				Metadata: map[string]any{
					"tid": tid,
				},
			}
		}
	}
	return task, nil
}

func (s *TaskService) GetTasksByName(ctx context.Context, username string, page int, pageSize int, start string, end string) ([]models.Task, error) {

	tasks, err := s.sqlTaskRepo.FindAllByName(ctx, username, page, pageSize, start, end)
	if err != nil {
		if customErr, ok := err.(*myerror.CustomError); ok {
			return nil, &myerror.CustomError{
				Code:        customErr.Code,
				Message:     "TaskService:GetTasksByName() failed",
				OriginError: err,
				Metadata: map[string]any{
					"username": username,
				},
			}
		} else {
			return nil, &myerror.CustomError{
				Code:        myerror.DefaultFailure,
				Message:     "TaskService:GetTasksByName() failed",
				OriginError: err,
				Metadata: map[string]any{
					"username": username,
				},
			}
		}
	}
	return tasks, nil
}

func (s *TaskService) UpdatePathByTid(ctx context.Context, tid, absPath string) error {

	err := s.sqlTaskRepo.UpdatePathByTid(ctx, tid, absPath)
	if err != nil {
		if customErr, ok := err.(*myerror.CustomError); ok {
			return &myerror.CustomError{
				Code:        customErr.Code,
				Message:     "TaskService:UpdatePathByTid() failed",
				OriginError: err,
				Metadata: map[string]any{
					"tid":     tid,
					"absPath": absPath,
				},
			}
		} else {
			return &myerror.CustomError{
				Code:        myerror.DefaultFailure,
				Message:     "TaskService:UpdatePathByTid() failed",
				OriginError: err,
				Metadata: map[string]any{
					"tid":     tid,
					"absPath": absPath,
				},
			}
		}
	}
	return nil
}

func (s *TaskService) GetTaskPath(ctx context.Context, tid string) (string, error) {
	task, err := s.sqlTaskRepo.GetByTid(ctx, tid)
	if err != nil {
		if customErr, ok := err.(*myerror.CustomError); ok {
			return "", &myerror.CustomError{
				Code:        customErr.Code,
				Message:     "TaskService:GetTaskPath() failed",
				OriginError: err,
				Metadata: map[string]any{
					"tid": tid,
				},
			}
		} else {
			return "", &myerror.CustomError{
				Code:        myerror.DefaultFailure,
				Message:     "TaskService:GetTaskPath() failed",
				OriginError: err,
				Metadata: map[string]any{
					"tid": tid,
				},
			}
		}
	}
	return task.AbsPath, nil
}

func (s *TaskService) GetCodePath(ctx context.Context, tid string) (string, error) {
	task, err := s.sqlTaskRepo.GetByTid(ctx, tid)
	if err != nil {
		if customErr, ok := err.(*myerror.CustomError); ok {
			return "", &myerror.CustomError{
				Code:        customErr.Code,
				Message:     "TaskService:GetCodePath() failed",
				OriginError: err,
				Metadata: map[string]any{
					"tid": tid,
				},
			}
		} else {
			return "", &myerror.CustomError{
				Code:        myerror.DefaultFailure,
				Message:     "TaskService:GetCodePath() failed",
				OriginError: err,
				Metadata: map[string]any{
					"tid": tid,
				},
			}
		}
	}
	return filepath.Join(task.AbsPath, utils.RepoName(task.RepoUrl)), nil
}

func (s *TaskService) GetHtmlPath(ctx context.Context, tid string) (string, error) {
	taskPath, err := s.GetTaskPath(ctx, tid)
	if err != nil {
		if customErr, ok := err.(*myerror.CustomError); ok {
			return "", &myerror.CustomError{
				Code:        customErr.Code,
				Message:     "TaskService:GetHtmlPath() failed",
				OriginError: err,
				Metadata: map[string]any{
					"tid": tid,
				},
			}
		} else {
			return "", &myerror.CustomError{
				Code:        myerror.DefaultFailure,
				Message:     "TaskService:GetHtmlPath() failed",
				OriginError: err,
				Metadata: map[string]any{
					"tid": tid,
				},
			}
		}
	}

	return filepath.Join(taskPath, "html"), nil
}

func (s *TaskService) GetModuleName(ctx context.Context, tid string) (string, error) {
	codePath, err := s.GetCodePath(ctx, tid)
	if err != nil {
		if customErr, ok := err.(*myerror.CustomError); ok {
			return "", &myerror.CustomError{
				Code:        customErr.Code,
				Message:     "TaskService:GetModuleName() failed",
				OriginError: err,
				Metadata: map[string]any{
					"tid": tid,
				},
			}
		} else {
			return "", &myerror.CustomError{
				Code:        myerror.DefaultFailure,
				Message:     "TaskService:GetModuleName() failed",
				OriginError: err,
				Metadata: map[string]any{
					"tid": tid,
				},
			}
		}
	}

	moduleName, err := utils.GetModuleName(codePath)
	if err != nil {
		if customErr, ok := err.(*myerror.CustomError); ok {
			return "", &myerror.CustomError{
				Code:        customErr.Code,
				Message:     "TaskService:GetTaskPath() failed",
				OriginError: err,
				Metadata: map[string]any{
					"tid": tid,
				},
			}
		} else {
			return "", &myerror.CustomError{
				Code:        myerror.DefaultFailure,
				Message:     "TaskService:GetTaskPath() failed",
				OriginError: err,
				Metadata: map[string]any{
					"tid": tid,
				},
			}
		}
	}

	return moduleName, nil
}

func (s *TaskService) UpdatePercentById(ctx context.Context, tid string, total int, covered int, percent float64) error {
	return s.sqlTaskRepo.UpdatePercentById(ctx, tid, total, covered, percent)
}
